package com.sffzh.util.format;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import com.google.gson.ExclusionStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.sffzh.constant.Time;
import com.sffzh.pojo.User;
import com.sffzh.util.format.GsonAnnotationExclusionStrategy.MainData;

/**
 * 生成固定格式的message用于向客户端传送数据：格式为：
 * {
 * 		msg:'',
 * 		status:'ok',
 * 		list:['123456'],
 * 		totalCount:2,
 * 		code:1000
 * }
 * @author sffzh
 *
 */
public class Message extends Object{
	private String msg;
	private String status="ok";
	private boolean isStatusOk;
	@SuppressWarnings("rawtypes")
	private List list;
	private Object[] array=new Object[0];
	private int totalCount;
	private int code;
	private Map<String, Object> map;
	private JSONArray jsonArray;
	private NullField nullField=NullField.EMPTYSTR;
	private String dateFormat=Time.defaultPattern();
	
	public enum NullField{
		NULL,
		EMPTYSTR,//空字符串，即""
		EXCLUDE//排除，即根本不包含此字段
		, NULLSTR//即"null"
	}
	
	private class Data implements MainData{
		public Data() {
		}
		@Expose  
		private String msg;
		@Expose  
		private String status;
		@Expose  
		private Object list;
		@Expose  
		private int totalCount;
		@Expose  
		private int code;
	}
	
	public Message(@SuppressWarnings("rawtypes") List list){
		setList(list);
	}
	public Message(Object list){
		setList(list);
	}
	public Message(Object[] list){
		setList(list);
	}
	
	public Message(String msg, boolean isStatusOk, int code) {
		super();
		this.msg = msg;
		setStatusOk(isStatusOk);
		setCode(code);
	}

	public Message(String msg, boolean isStatusOk) {
		super();
		this.msg = msg;
		setStatusOk(isStatusOk);
	}

	public Message(String msg, boolean isStatusOk, @SuppressWarnings("rawtypes") List list, int code) {
		super();
		this.msg = msg;
		setStatusOk(isStatusOk);
		setList(list);
		setCode(code);
	}
	public Message(String msg, boolean isStatusOk, Object[] list, int code) {
		super();
		this.msg = msg;
		setStatusOk(isStatusOk);
		setList(list);
		setCode(code);
	}
	public Message(String msg, boolean isStatusOk, Object list, int code) {
		super();
		this.msg = msg;
		setStatusOk(isStatusOk);
		setList(list);
		setCode(code);
	}



	public Message(String msg2, boolean isStatusOk2, Object list) {
		this.msg=msg2;
		setStatusOk(isStatusOk2);
		setList(list);
	}
	
	private Message() {
	}
	public String getMsg() {
		return msg;
	}
	public Message setMsg(String msg) {
		this.msg = msg;
		return this;
	}
	public String getStatus() {
		return status;
	}
	public void setStatus(String status) {
		this.status = status;
		if("ok".equals(status))this.isStatusOk=true;
		else this.isStatusOk=false;
	}
	public boolean statusIsOk() {
		return isStatusOk;
	}
	public void setStatusOk(boolean isStatusOk) {
		this.isStatusOk = isStatusOk;
		this.status=isStatusOk?"ok":"error";
	}
	public Object getList() {
		if(list==null)return array;
		return list;
	}
	public void setList(List<?> list) {
		this.list = list;
		this.totalCount=list.size();
	}
	public void setList(Object[] array){
		this.array=array;
		this.totalCount=array.length;
	}
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void setList(Object object){
		if(object==null)return;
		if(object.getClass().isArray()){
			this.array=(Object[]) object;
			this.totalCount=this.array.length;
			return;
		}
		this.list=new ArrayList();
		list.add(object);
		this.totalCount=1;
	}
	
	public int getTotalCount() {
		return totalCount;
	}
	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}
	public int getCode() {
		return code;
	}
	public Message setCode(int code) {
		this.code = code;
		return this;
	}

	public String toJson(){
		return toJson(false,null);
	}
	
	public String toJson(boolean checkExposeAnnotation){
		return toJson(checkExposeAnnotation,null);
	}
	
	/**
	 * 字段过滤：有两种模式：如果参数exposeVersion以半角冒号开头，则以perfectJson方法进行过滤，即递归检查整个json串，保留参数中定义的字段；
	 * 否则将exposeVersion作为版本名称，按注解的jsonVersion进行过滤。后一种效率更高。
	 * 整理json串，只保留指定的字段。（比起此方法更推荐使用注释法进行字段过滤）
	 * @param exposeVersion
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public  String toJson(String exposeVersion){
		if(exposeVersion!=null&&exposeVersion.startsWith(":")){

			String json=this.toJson();
			return JsonConvert.perfectJsonStr(json, exposeVersion.substring(1)+",status,code,msg,totalCount");
		
		}
		return toJson(true,exposeVersion);
	}
	
	/**
	 * 将消息对象转化为json
	 * @param checkExposeAnnotation
	 * @return
	 */
	private String toJson(boolean checkExposeAnnotation,String version) {
		GsonBuilder gsonBuilder=new GsonBuilder();
		if(version!=null&&version.indexOf(',')>0){//一次转换只能有单一一种版本
			version=null;
		}
		  
		if(checkExposeAnnotation){
			if(version==null){
				gsonBuilder.excludeFieldsWithoutExposeAnnotation(); //不导出实体中没有用@Expose注解的属性
			}else{
				ExclusionStrategy exclusionByJsonType = new GsonAnnotationExclusionStrategy(version);
				gsonBuilder.setExclusionStrategies(exclusionByJsonType);
			}
		}
		if(this.nullField!=NullField.EXCLUDE){
			gsonBuilder.serializeNulls();
		}
   		Gson gson = 
			gsonBuilder
			.setDateFormat(this.dateFormat)
			.create();
		Data data=new Data();
		data.code=this.code;
		data.status=this.status;
		data.msg=this.msg;
		data.totalCount=this.totalCount;
		if(this.jsonArray!=null){
			if(data.msg==null)data.msg="";
			data.list=new ArrayList<JSONObject>();
			String json=gson.toJson(data);
			JSONObject o=JSONObject.fromObject(json);
			o.put("list", this.jsonArray);
			return o.toString();
		}
		if(this.map!=null){
			setList(this.map);
		}
		data.list=this.list==null?array:this.list;
		String json=gson.toJson(data);
		switch(this.nullField){
		case EMPTYSTR:json=json.replace("\":null,\"", "\":\"\",\"").replace("\":null}","\":\"\"}");break;
		case NULLSTR:json=json.replace("\":null,\"", "\":\"null\",\"").replace("\":null}","\":\"null\"}");break;
		default :break;
		}
		return json;
	}
	
	public static void main(String[] args) {//测试程序
//		System.out.println(new Message("测试",true,"{\"a\":\"内容\",\"b\":\"1\"}",123).toJson());
//		p.setStartTime(new Date());
		User user=new User();
		user.setName("鲁瑞章");
		user.setAge(99);
		user.setNickname("枫子皓");
		user.setBirthday(new Date());
		user.setEmail("sffzh@sina.com");
		System.err.println(Message.json(user).toJson("uuuu"));
		System.err.println(Message.json(user).toJson("aaaa"));
//		System.err.println(Message.json(p).toJson(true));
//		System.err.println(Message.json(p).toJson());
	

		List<Integer> list=Arrays.asList(new Integer[]{1,2,3,4,5});
		System.err.println(json(list));
	
	}
	
	public String toString(){
		return toJson();
	}

	/**
	 * 这个方法用于在List为null或者已知List中的对象类型时，新增一个对象
	 * @param object
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Message addContent(Object object){
		if(this.jsonArray!=null){
			this.jsonArray.add(JSONObject.fromObject(object));
			return this;
		}
		if(this.list==null)this.list=new ArrayList();
		this.list.add(object);
		return this;
	}

	/**
	 * 这个方法用于在没有预设List内容的情况下，向message中增加一个map对象，并向其中添加键值对
	 * 注意：调用此方法后，设定好的list将被清空！！！此方法不能和其他设置list的方法配合使用，只能反复调用这个方法直到完成添加一个完整的Map对象
	 * @param string
	 * @param obj
	 * @return
	 */
	public Message addContent(String string, Object obj) {
		if(this.map==null)this.map=new HashMap<String, Object>();
		this.map.put(string, obj);
		return this;
	}
	
	/**
	 * 这个方法用于向List内容中已有的对象内添加字段
	 * 注意：一旦使用此方法，将无法使用注释法过滤字段
	 * 当list中条数较多时，不推荐使用此方法
	 * @param key
	 * @param value
	 * @param index
	 * @return
	 */
	public Message addContent(String key,Object value,int index){
		if(this.jsonArray!=null){
			for(int i=0;i<jsonArray.size();i++){
				if(i==index)jsonArray.getJSONObject(i).put(key, (value instanceof Date)?DateUtil.formatDateTime((Date) value):value);
				else jsonArray.getJSONObject(i).put(key, null);
			}
			return this;
		}
		GsonBuilder gsonBuilder=new GsonBuilder();
   		Gson gson = 
			gsonBuilder.serializeNulls()
			.setDateFormat("yyyy-MM-dd HH:mm:ss")
			.create();
   		List<JSONObject> jsonList=new ArrayList<JSONObject>();
   		if(list!=null)
		for(int i=0;i<list.size();i++){
			JSONObject  json=JSONObject.fromObject(gson.toJson(list.get(i)).replace("\":null,\"", "\":\"\",\"").replace("\":null}","\":\"\"}"));
			if(i==index){
				json.put(key, value);		
			}
			jsonList.add(json);
		}
   		else if(array!=null){
   			
   			for(int i=0;i<array.length;i++){
   				JSONObject  json=JSONObject.fromObject(gson.toJson(array[i]).replace("\":null,\"", "\":\"\",\"").replace("\":null}","\":\"\"}"));
   				if(i==index){
   					json.put(key, value);		
   				}
   				jsonList.add(json);
   			}
   		}
   		if(jsonList.size()>0){
   	   		this.jsonArray=JSONArray.fromObject(jsonList);
   	   		this.totalCount=this.jsonArray.size();
   		}
   		return this;
	}

	/**
	 * 静态方法json的效果和用new来创建message是一样的
	 * @param list
	 * @return
	 */
	public static Message json(List<?> list) {
		if(list==null)return new Message();
		return new Message(list);
	}
	public static Message json(Object obj) {
		if(obj==null)return new Message();
		return new Message(obj);
	}

	public enum Case{
		FORMAT_ERROR,//格式错误，对应代码
		PUBIC_INFO_MISS,//公共字段缺失
		KEY_MISS,//关键参数缺失
		DATA_WRONG, //数据库数据异常
		PARAMETER_ERROR,//请求方发送的参数有问题
		TIME_ERROR, //客户端时间异常
		SESSION_WRONG,//session中存的数据有错误
		
		DATA_EMPTY_CHANGE,//查询结果为空，将要自动变更返回的数据
	}
	
	/**
	 * 这个方法用于在客户端请求接口的参数有异常导致功能异常时，向客户端返回错误信息
	 * @param e 发生的错误类型
	 * @return
	 */
	public static Message error(Case e){
		return error(e,null);
	}
	/**
	 * 这个方法用于在客户端请求接口的参数有异常导致功能异常时，向客户端返回错误信息
	 * @param e 发生的错误类型
	 * @return
	 */
	public static Message error(Case e,String msg){
		int code=0;
		Message m=new Message(msg,false,code);
		return m.setCaseCode(e,msg);
	}
	
	/**
	 * 这个方法用于客户端执行一个简单操作，仅需要返回操作是否成功的提示时，向客户端返回一个成功标识
	 * @param msg 提示语，可以为空
	 * @return
	 */
	public static Message success(String msg){
		return new Message(msg, true,1000);
	}
	/**
	 * 这个方法用于客户端执行一个简单操作，仅需要返回操作是否成功的提示时，向客户端返回一个失败标识
	 * @param msg 提示语，可以为空
	 * @return
	 */
	public static Message fail(String msg){
		return new Message(msg, false,1001);
	}
	
	
	/**
	 * 整理json串，只保留指定的字段。（比起此方法更推荐使用注释法进行字段过滤）
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public String toJson(String[] remainKeys){
		String json=this.toJson();
		return JsonConvert.perfectJson(json, remainKeys);
	}

	public String toString(String remainKeys){
		return toJson(remainKeys);
	}
	public String toString(String[] remainKeys){
		return toJson(remainKeys);
	}
	
	/**
	 * 这个方法用来快速按情景设置code值。不影响status
	 * code说明：负数表示异常类的错误，
	 * 1000表示结果为正确；
	 * 1001表示通信正常结果为错误
	 * 其中-15**表示可能有人为因素的错误
	 * 100**表示系统其他错误
	 * 8000-9999为变更数据意义标识，表示原计划失效，采用另外的特殊数据。
	 * 10000-19999为自定义标识区间，用于表示各方法内当前临时约定的意义。
	 * @param e
	 * @param msg
	 */
	public Message setCaseCode(Case e, String msg) {
		if(e==null){
			this.msg=msg;
			return this;
		}
		switch(e){
		case TIME_ERROR:
			code= 10001;if(msg==null)this.msg="客户端时间异常";break;
		case FORMAT_ERROR:
			code=-1501;if(msg==null)this.msg="json格式错误";break;
		case PUBIC_INFO_MISS:
			code=-1502;if(msg==null)this.msg="公共字段缺失";break;
		case KEY_MISS:
			code=-1503;if(msg==null)this.msg="关键字缺失";break;
		case DATA_WRONG:
			code=-1400;if(msg==null)this.msg="数据库数据异常";break;
		case DATA_EMPTY_CHANGE:
			code= 8000;if(msg==null)this.msg="查询结果为空";break;
		case PARAMETER_ERROR:
			code=-1504;if(msg==null)this.msg="客户端请求参数有误";break;
		default:
			break;
		}
		return this;
	}
	
	/**
	 * 这个方法用来快速按情景设置code值。如果msg为Null,则将设置默认情景下的msg,不影响status
	 */
	public Message setCaseCode(Case e){
		return setCaseCode(e, this.msg);
	}
	public NullField getNullField() {
		return nullField;
	}
	public Message setNullField(NullField nullField) {
		this.nullField = nullField;
		return this;
	}
	public String getDateFormat() {
		return dateFormat;
	}
	public Message setDateFormat(String dateFormat) {
		if(dateFormat!=null)
		this.dateFormat = dateFormat;
		return this;
	}
	public Message setDateFormat(Time.Pattern dateFormat) {
		return setDateFormat(Time.getPatternStr(dateFormat));
	}
 
}
